#pragma once

#include "vec2.h"

OPEN_JLIB_NS


struct Box2 {

  f32v4 p;

  inline Box2 () noexcept = default;
  inline Box2 (f32v4 p) noexcept : p(p) {
  }
  inline Box2 (f32 minx, f32 miny, f32 maxx, f32 maxy) {
    asm volatile (R"(
    zip1 %[dst].2s, %[op1].2s, %[op2].2s
    ins %[dst].s[2], %[op3].s[0]
    ins %[dst].s[3], %[op4].s[0])"
    : [dst]"=&x"(p): [op1]"x"(minx), [op2]"x"(miny), [op3]"x"(maxx), [op4]"x"(maxy));
  }
  inline Box2 (Vec2 min, Vec2 max) {
    asm volatile (R"(
    zip1 %[dst].2d, %[op1].2d, %[op2].2d)"
    : [dst]"=x"(p): [op1]"x"(min.p), [op2]"x"(max.p));
  }
  inline Box2 (const f32* m) noexcept {
    asm volatile (R"(
    ld1 { %[dst].4s }, [%[mem]])"
    : [dst]"=x"(p): [mem]"r"(m));
  }


  inline Box2& operator&= (Box2 v) noexcept {
    f32v4 t;
    asm volatile (R"(
    fmin %[tmp].4s, %[op1].4s, %[op2].4s
    fmax %[op1].4s, %[op1].4s, %[op2].4s
    ins %[op1].d[1], %[tmp].d[1])"
    : [op1]"+x"(p), [tmp]"=&x"(t): [op2]"x"(v.p));
    return *this;
  }
  inline Box2& operator|= (Box2 v) noexcept {
    f32v4 t;
    asm volatile (R"(
    fmax %[tmp].4s, %[op1].4s, %[op2].4s
    fmin %[op1].4s, %[op1].4s, %[op2].4s
    ins %[op1].d[1], %[tmp].d[1])"
    : [op1]"+x"(p), [tmp]"=&x"(t): [op2]"x"(v.p));
    return *this;
  }


  inline Box2 operator& (Box2 v) const noexcept {
    f32v4 r, t;
    asm volatile (R"(
    fmin %[tmp].4s, %[op1].4s, %[op2].4s
    fmax %[dst].4s, %[op1].4s, %[op2].4s
    ins %[dst].d[1], %[tmp].d[1])"
    : [dst]"=x"(r), [tmp]"=&x"(t): [op1]"x"(p), [op2]"x"(v.p));
    return *this;
  }
  inline Box2 operator| (Box2 v) const noexcept {
    f32v4 r, t;
    asm volatile (R"(
    fmax %[tmp].4s, %[op1].4s, %[op2].4s
    fmin %[dst].4s, %[op1].4s, %[op2].4s
    ins %[dst].d[1], %[tmp].d[1])"
    : [dst]"=x"(r), [tmp]"=&x"(t): [op1]"x"(p), [op2]"x"(v.p));
    return *this;
  }


  inline Vec2 operator~ () const noexcept {
    f64 r;
    asm volatile (R"(
    ins %[dst].d[0], %[src].d[1]
    fsub %[dst].2s, %[dst].4s, %[src].2s)"
    : [dst]"=&x"(r): [src]"x"(p));
    return r;
  }


  inline f32 x () const noexcept {
    return p[0];
  }
  inline f32 y () const noexcept {
    return p[1];
  }
  inline f32 X () const noexcept {
    return p[2];
  }
  inline f32 Y () const noexcept {
    return p[3];
  }


  inline Vec2 xy () const noexcept {
    f64 r;
    asm volatile (R"()"
    : [dst]"=x"(r): "[dst]"(p));
    return r;
  }
  inline Vec2 xY () const noexcept {
    f64 r;
    asm volatile (R"(
    ins %[dst].s[1], %[src].s[3])"
    : [dst]"=x"(r): [src]"[dst]"(p));
    return r;
  }
  inline Vec2 Xy () const noexcept {
    f64 r;
    asm volatile (R"(
    ins %[dst].s[0], %[src].s[2])"
    : [dst]"=x"(r): [src]"[dst]"(p));
    return r;
  }
  inline Vec2 XY () const noexcept {
    f64 r;
    asm volatile (R"(
    ins %[dst].d[0], %[src].d[1])"
    : [dst]"=x"(r): [src]"x"(p));
    return r;
  }


  inline bool contains (Vec2 v) const noexcept {
    f32v4 t0, t1;
    s32 r;
    asm volatile (R"(
    zip1 %[tp0].2d, %[op1].2d, %[op2].2d
    zip2 %[tp1].2d, %[tp0].2d, %[op1].2d
    fcmgt %[tp0].4s, %[tp0].4s, %[tp1].4s
    addv %s[dst], %[tp0].4s)"
    : [dst]"=x"(r), [tp0]"=&x"(t0), [tp1]"=x"(t1): [op1]"x"(p), [op2]"x"(v.p), [cmp]"K"(avx::NLE_UQ));
    return r == 0;
  }
  inline bool contains (Box2 v) const noexcept {
    f32v4 t0, t1;
    s32 r;
    asm volatile (R"(
    ins %[tp0].d[0], %[op1].d[0]
    ins %[tp0].d[1], %[op2].d[1]
    ins %[tp1].d[0], %[op2].d[0]
    ins %[tp1].d[1], %[op1].d[1]
    fcmgt %[tp0].4s, %[tp0].4s, %[tp1].4s
    addv %s[dst], %[tp0].4s)"
    : [dst]"=x"(r), [tp0]"=&x"(t0), [tp1]"=x"(t1): [op1]"x"(p), [op2]"x"(v.p), [cmp]"K"(avx::NLE_UQ));
    return r == 0;
  }
  inline bool intersect (Box2 v) const noexcept {
    f32v4 t0, t1;
    s32 r;
    asm volatile (R"(
    zip1 %[tp0].2d, %[op1].2d, %[op2].2d
    zip2 %[tp1].2d, %[op2].2d, %[op1].2d
    fcmge %[tp0].4s, %[tp0].4s, %[tp1].4s
    addv %s[dst], %[tp0].4s)"
    : [dst]"=x"(r), [tp0]"=&x"(t0), [tp1]"=x"(t1): [op1]"x"(p), [op2]"x"(v.p), [cmp]"K"(avx::NLT_UQ));
    return r == 0;
  }
};


CLOSE_JLIB_NS